;
;
;
;=============================================================
;  <SGEN> - CP/M MULTI-TRACK SYSTEM GENERATION UTILITY       =
;           USED FOR NORMAL OR LARGE ( > 2 SYSTEM TRACKS)    =
;           SYSTEM GENERATION.  MAY BE USED IN PLACE OF      =
;           SYSGEN.                                          =
;  DONALD E. KILLEN    REV 1.00    19 NOV 80                 =
;=============================================================
;
;  MENU / PROMPT DRIVEN, SIMILAR TO SYSGEN, EXCEPT THAT SGEN
;  WILL ASK USER FOR THE NUMBER OF SYSTEM TRACKS TO WRITE.
;
;  NOTE:  REMEMBER TO TELL XBOOTXX.HEX HOW MANY TOTAL SECTORS
;         ARE IN THE SYSTEM, NOT INCLUDING THE BOOT ITSELF
;         (WHICH IS 1 SECTOR LONG).
;
;============================================================
;
	TITLE S G E N  -  REV 1.00 - 19 NOV 1980
	.Z80
	.XLIST
	  INCLUDE  CLIB
	  INCLUDE  MACROZ
	.LIST
	.Z80
;
NSECTS	EQU	26D		; NO. SECTORS ON A TRACK..
DMASTART EQU	900H		; BEGINNING DMA ADDRESS.
;
	CSEG
;
;
START:	SWIN  OLDSP,NEWSP  ; SAVE ALL REG & SETUP OWN STACK.
;
RESTART: PRINT	<CR,LF,'S G E N  1.00 OF 19 NOV 80',CR,LF>
	PRINT	'ENTER NUMBER OF SYSTEM TRACKS 1-9 (CR=2): '
	CALL	GETCH	; GET KEYBOARD CHAR (ASCII IN -A-,
			;  AND BINARY IN -B- )
	LD	E,A	; TEMP STASH ASCII VALUE IN E.
	LD	(NTRKS),A  ; STASH ASCII # TRACKS
	STORE   NTRKSB,B   ;  .. & BINARY.
	LD	A,E	; RESTORE ASCII VALUE IN A.
	CP	CR	; IF CAR. RET., IT IS 2 TRACK SYSTEM.
	JR	Z,TWOTRK
	CP	'2'	; CHECK IF 2 TRACKS.
	JR	Z,TWOTRK
	CP	'3'	; CHECK IF GE THREE TRACKS.
	JP	M,NTRK	; LESS THAN THREE, GO ON
	PRINT	<CR,LF,'ARE YOU SURE - 3 OR MORE TRACKS ? '>
	CHARIN		; GET RESPONSE
	CP	'Y'	; IS IT UC 'Y' ?
	JR	Z,YESY	; HOP IF YES.
	SUB	20H	; SEE IF IT MIGHT BE LC 'Y'
	CP	'Y'
	JP	NZ,RESTART  ; USER UNSURE, SO START OVER.
YESY:	JR	NTRK	; GO DO IT.
TWOTRK:	PRINT	<CR,LF,'DOING STANDARD TWO-TRACK SYSTEM **'>
	JR	GOTOIT	; GO DO IT...
;
NTRK:	PRINT 	<CR,LF,'DOING NON-STANDARD '>
	PRINT	NTRKS,1,A	; PRINT # TRACKS.
	PRINT	' TRACK SYSTEM **'
;
GOTOIT:
	PRINT	<CR,LF,'ENTER SOURCE DRIVE (CR IF IN MEMORY): '>
	CALL	GETCH		; GET SOURCE DRIVE OR CODE.
	LD	E,A		; TEMP STASH ASCII DRIVE CODE.
	LD	(SCA),A		; ASCII SOURCE DRIVE # TO MEM
	STORE	SOURCE,B	; & BINARY VALUE.
	LD	A,E		; & RESTORE ASCII IN A.
	CP	CR		; IF CR, SYSTEM CODE IS IN MEM.
	JR	Z,INMEM		; -- SO HOP TO IT.
	CALL	CHKALPHA	; SEE IF IT IS AN ALPHA CHAR.
	JR	NZ,GOTOIT	; & ASK AGAIN IF NOT.
;
; ASSUMING IT IS ON A DISK, GET IT IN MEMORY.
;
	PRINT	<CR,LF,'SOURCE ON '>
	PRINT	SCA,1,A		; PRINT SOURCE DRIVE NAME
	PRINT	' , TYPE CR TO READ *'
	CALL	GETCH		; GET USER RESPONSE.
	CP	CR
	JP	NZ,RESTART	; HEY, IF USER DOESN'T
;                                 TYPE IN A CR, HE MUST WANT SOMETHING.
;
	CALL	GETSYS		; GET SYSTEM TO MEMORY AT 900H.
;
; WAS IN MEMORY, OR ELSE IT IS AFTER CALL TO GETSYS:

;
INMEM:	PRINT	<CR,LF,'SOURCE IS IN MEMORY ***'>
WR1:	PRINT	<CR,LF,'DESTINATION DRIVE: (CR TO EXIT TO CP/M) '>
	CALL	GETCH		; GET DEST DRIVE LETTER.. OR CR.
	LD	E,A		; TEMP STASH ASCII VALUE
	LD	(DCA),A		; PUT ASCII IN MEM
	STORE	DEST,B		; & BINARY,
	LD	A,E		; & RESTORE ASCII IN A.
	CP	CR		; IS IT A CR ?
	JP	Z,NOWRIT	; IF SO, REBOOT CP/M.
	CALL	CHKALPHA	; SEE IF IT IS REALLY ALPHA.
	JR	NZ,WR1		; & ASK AGAIN IF NOT.
;
; HERE WE HAVE SYSTEM IN MEMORY - WRITE TO DESTINATION.
;
WR2:	PRINT	<CR,LF,'DESTINATION = DRIVE '>
	PRINT	DCA,1,A		; PRINT DEST. DRIVE LETTER.
	PRINT	', TYPE CR TO WRITE, TAB TO REBOOT **'
	PRINT			; CR,LF
	CALL	GETCH		; GET THE DECISION
	CP	TAB		; IS IT TAB KEY ?
	JR	Z,REBOOT	; IF YES, HOP TO BOOT (WARM)
	CP	CR		; CHECK - IS IT A CR ?
	JR	NZ,WR2		; NO ? .. MUST WANT TO CHANGE MIND.
;
	CALL	PUTSYS		; WRITE SYSTEM ON DESTINATION.
;
	PRINT	<CR,LF,'SYSTEM WRITTEN ON DRIVE '>
	PRINT	DCA,1,A		; PRINT DESTINATION DRIVE LTR.
	PRINT	', - CR TO DO AGAIN, TAB TO REBOOT: '
	CALL	GETCH		; GET DECISION
	CP	CR		; IS IT A CR ?
	JP	Z,WR1		; YES, SEE IF HE WANTS SAME DRIVE.
	CP	TAB		; IS IT A TAB ?
	JR	Z,REBOOT	; DO WARM BOOT IF YES.
	JP	RESTART		; , OTHERWISE START ALL OVER.
;
; TIME TO REBOOT CP/M HERE:
;
NOWRIT:
REBOOT: SWOT OLDSP,NEWSP	; RESTORE CP/M REG & STACK..
	CALLBIOS	DWBOOT	; & DO A WARM BOOT FUNCTION.
;
; SHOULD NEVER GET HERE.
;
	JP	0000		; DISASTER - DO COLD BOOT.
;
;============================================================
;  SUBROUTINES:  
;
;  GETSYS:  USES <SOURCE> - READS SYSTEM TO MEMORY.
;  PUTSYS   USES <DEST>   - WRITES SYSTEM TO DISK.
;
;    BOTH USE <NTRKSB> = BINARY # TRACKS.
;
;    BOTH USE CBIOS AND / OR BDOS (2.2) FUNCTIONS.
;
;============================================================
;
;  GET SYSTEM FROM TRACK 0, SECTOR 1 THRU SECTOR 26 OF LAST
;  TRACK   -  TO MEMORY STARTING AT 900H.
;
GETSYS:	PUSHALL
	CALL	INITRW		; INITIALIZE TRK, SEC, DMAADR.
	LD	HL,SOURCE
	LD	C,(HL)
	CALLBIOS DSELDSK	; SELECT SOURCE DRIVE.
;
GET1:	LD	HL,CURTRK
	LD	C,(HL)
	CALLBIOS DSETTRK	; SELECT TRACK
;
GET2:	LD	HL,CURSEC
	LD	C,(HL)
	CALLBIOS DSETSEC	; SELECT SECTOR TO READ.
;
	LD	BC,(DMAADR)
	CALLBIOS DSETDMA	; SET TRANSFER ADDRESS.
;
	CALLBIOS DREAD		; READ THE SECTOR.
;
	CALL	NXS		; NEXT SECTOR UNLESS LAST,
	JP	Z,NXRDTK	; .. HOP IF LAST ON THIS TRACK.
	JP	GET2		; OTHERWISE DO THE NEXT ONE.
;
NXRDTK:	CALL	NXT		; GO TO NEXT TRACK UNLESS LAST.
	JP	Z,DONE		; HOP IF LAST TRACK,
	JP	GET1		; OTHERWISE DO NEXT TRACK.
;
DONE:	POPALL			; & RESTORE REGISTERS..
	RET
;
; BUMP THE DMA ADDRESS BY 128:
;
BUMP:	LD	HL,(DMAADR)
	LD	DE,128D
	ADD	HL,DE
	LD	(DMAADR),HL
	RET
;
;  NXT  -- GO TO NEXT TRACK UNLESS LAST, IN WHICH CASE RET Z.
;
NXT:	LD	A,(CURTRK)	; GET CURRENT TRACK NO.
	LD	E,A		; TEMP STASH...
	LD	HL,NTRKSB
	LD	A,(HL)		; GET NO. OF LAST TRACK TO DO.
	SUB	1		; DOING NTRKSB - 1 (FIRST IS 0)..
	CP	E		; DID WE JUST FINISH LAST ONE ?
	JR	Z,DONET		; HOP IF YES.
	LD	A,E		; GET CURRENT TRK BACK &
	INC	A		; OTHERWISE INCR. TRACK NO.
	LD	(CURTRK),A	; & PUT IT IN MEM.
	LD	A,1		; SET CURRENT SECTOR
	LD	(CURSEC),A	;  .. EQUALS 1.
	CALL	BUMP		; & INCR. DMA ADDRESS BY 128.
	BIT	0,A		; FORCE Z FLAG OFF.
DONET:	RET			; & RETURN...
;
;  NXS  -- GO TO NEXT SECTOR UNLESS LAST, IN WHICH CASE RET Z.
;
NXS:	LD	A,(CURSEC)	; GET CURRENT SECTOR NO.
	LD	B,NSECTS	; GET NO. SECTORS PER TRACK..
	CP	B		; DID WE JUST DO THE LAST ONE ?
	JR	Z,DONES		; HOP IF YES.
	INC	A		; OTHERWISE INCR. SECTOR NO.
	LD	(CURSEC),A	; & PUT IT IN MEM.
	CALL	BUMP		; & INCR. DMA ADDRESS BY 128.
	LD	B,0FFH
	BIT	0,B		; FORCE Z FLAG OFF.
DONES:	RET			; & RETURN.
;
;  INITIALIZE PARAMETERS FOR ENTRY TO PUTSYS & GETSYS -
;
INITRW:	XOR	A		; GET A ZERO
	LD	(CURTRK),A	; SET CURRENT (FIRST) TRACK #
	LD	A,1
	LD	(CURSEC),A	; SET FIRST SECTOR NO.
	LD	BC,DMASTART	; GET STARTING DMA ADDRESS.
	LD	(DMAADR),BC	; & PUT IT IN MEM.
	RET
;
;
;
;============================================================
;
;  PUTSYS  - JUST THE INVERSE OF GETSYS.
;
PUTSYS:	PUSHALL			; SAVE REGISTERS.
	CALL	INITRW		; INITIALIZE TRK, SEC, DMAADR
	LD	HL,DEST
	LD	C,(HL)
	CALLBIOS DSELDSK	; SELECT DESTINATION DRIVE.
;
PUT1:	LD	HL,CURTRK	;
	LD	C,(HL)		; SELECT TRACK
	CALLBIOS DSETTRK	; SELECT TRACK.
;
PUT2:	LD	HL,CURSEC
	LD	C,(HL)
	CALLBIOS DSETSEC	; SELECT SECTOR.
;
	LD	BC,(DMAADR)
	CALLBIOS DSETDMA	; SET TRANSFER ADDRESS.
;
	CALLBIOS DWRITE		; WRITE THE SECTOR.
;
	CALL	NXS		; DO NEXT SECTOR UNLESS LAST.
	JP	Z,NXWRTK	;  HOP IF IT WAS LAST ON TRACK.
	JP	PUT2		; OTHERWISE, DO NEXT SECTOR.
;
NXWRTK:	CALL	NXT		; DO NEXT TRACK UNLESS LAST.
	JP	Z,DONE		; HOP (RETURN) IF LAST,
	JP	PUT1		; OTHERWISE, WRITE NEXT TRACK.
;
;  SUBROUTINE TO GET CHARACTER FROM KEYBOARD AND TEST FOR
;  VALIDITY (A-O) OR CONTROL CHARACTER (CR, TAB).
;
;  RETURNS ASCII CHARACTER IN -A- AND
;         BINARY EQUIVALENT IN -B- ; IF NOT (UC OR LC) A-O,
;         THEN RETURNS B = 0FFH.
;
GETCH:	CHARIN		; GET CHARACTER TO -A-
	LD	E,A	; STASH IT IN <E>
	CP	CR	; IS IT A CR ?
	JR	Z,CONT	; HOP IF YES.
	CP	TAB	; IS IT TAB KEY ?
	JR	Z,CONT	; HOP IF YES.
	CP	3AH	; IS IT NUMERIC ?
	JP	M,NUMBR	; HOP IF YES.
	CP	60H	; IS IT LOWER-CASE ?
	JP	M,UCASE	; HOP IF UPPER CASE.
	SUB	20H	; CONVERT LC TO UC.
	LD	E,A	; MODIFY <E> STASH.
UCASE:	CP	41H	; IS IT (LESS THAN) 'A' ?
	JP	M,TRYAGN ; IF YES, ILLEGAL CHAR, DO OVER.
	CP	4FH	; IS IT (GREATER THAN) 'O' ?
	JP	P,TRYAGN ; IF YES, ILLEGAL, DO OVER.
	SUB	41H	; IS UC A-O; MAKE IT BINARY.
	JR	OVER1
NUMBR:	SUB	30H	; CONVERT NUMERIC TO BINARY.
OVER1:	LD	B,A	; PUT BINARY IN <B>
	LD	A,E	; & RESTORE ASCII TO -A-
	RET
;
TRYAGN:	PRINT	<CR,LF,'** USE DRIVE A-O ** RE-ENTER NAME: '>
	JR	GETCH	; TRY AGAIN...
;
CONT:	LD	B,0FFH	; WE HAVE CONTROL CHAR, SET B = FFH.
	RET		; & RETURN WITH ASCII IN -A-.
;
;  CHECK <A> FOR VALID UC OR LC ALPHA CHAR.
;  PRESERVE <A>.  SET Z IF VALID ALPHA, NZ IF NOT.
;
CHKALPHA: LD	E,A	; PRESERVE <A>
	CP	41H	; IS IT UC 'A' OR ABOVE ?
	JP	M,BADA	; NO (IT IS PROB. NUMERIC)

	CP	5BH	; IS IT UC & BETWEEN A & Z ?
	JP	M,OK2
	CP	61H	; IS IT LC 'A' OR ABOVE ?
	JP	M,BADA	; BETWEEN UC 'Z' & LC 'A' - DON'T USE.
	CP	7BH	; IS IT ABOVE LC 'Z' ?
	JP	M,OK2	; IF NOT, USE IT.
BADA:	CP	0FFH	; FORCE NZ FLAG.
CHKEX:	LD	A,E	;  RESTORE VALUE TO A.
	RET		;   & RETURN.
;
OK2:	CP	A	; SET THE Z FLAG,
	JR	CHKEX	;  & GO RETURN..
;
;
;==========================================================
;
;  DATA SEGMENT:
;
	DSEG
;
SOURCE:	DS	1	; SOURCE DRIVE, BINARY
SCA:	DS	1	; SOURCE DRIVE, ASCII
DEST:	DS	1	; DESTINATION DRIVE, BINARY
DCA:	DS	1	; DESTINATION DRIVE, ASCII
NTRKS:	DS	1	; NO. TRACKS, ASCII
NTRKSB:	DS	1	; NO. TRACKS, BINARY
CURTRK:	DS	1	; CURRENT TRACK
CURSEC:	DS	1	; CURRENT SECTOR
DMAADR:	DS	2	; DISK MEM. ADDRESS (TRANSFER)
;
OLDSP:	DS	2	; CALLER'S STACK POINTER TEMP.
NEWSP:	DW	STACK	; NEW STACK POINTER...
TSPO:	DS	2	; TEMP OLD SP
TSPN:	DS	2	; TEMP NEW SP
;
	DS	128D	; <SGEN> STACK
STACK	EQU	$
;
	END
;
;
